package gwtgaetools.shared.model;

import java.util.ArrayList;

import javax.jdo.annotations.Extension;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.Inheritance;
import javax.jdo.annotations.InheritanceStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import com.google.gwt.user.client.rpc.IsSerializable;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
@Inheritance(strategy = InheritanceStrategy.SUBCLASS_TABLE)
public abstract class BaseObject<T extends BaseObject<T, PE>, PE extends PropertyEnum<PE, T>> implements IsSerializable {

	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	@Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
	private String id;
	
	public String getId() 		{ return id; }
	public void setId(String id) 	{ this.id = id; 		}

	@Extension(vendorName = "datanucleus", key = "gae.unindexed", value = "true")
	private ArrayList<String> properties = new ArrayList<String>();

	public abstract PE[] propNames();
	
	public Boolean 	getBoolean(PE pe) { return Boolean.parseBoolean(properties.get(pe.index())); 	}
	public Float 	getFloat(PE pe) 	{ return Float.parseFloat(properties.get(pe.index()));		}
	public Integer 	getInteger(PE pe) { return Integer.parseInt(properties.get(pe.index()));		}
	public String 	getString(PE pe) 	{ return properties.get(pe.index());	 					}
	
	ArrayList<String> getProperties() { return properties; }
	
	public int index() { return -1; }
	
	public String 	getProperty(PE b) 	{ return getProperty(b.index());	 	}
	
	public void setProperty(PE b, String value) 	{ setProperty(b.index(), value); 	}
	public void setBoolean(PE b, Boolean value) 	{ setProperty(b.index(), value.toString()); 	}
	public void setFloat(PE b, Float value) 			{ setProperty(b.index(), value.toString()); 		}
	public void setInteger(PE b, Integer value) 	{ setProperty(b.index(), value.toString()); }	

	public String getProperty(int i) { return getProperties().get(i); }
	public void setProperty(int index, String s) 			{ properties.set(index, s); 	}

	public BaseObject(T in) {
		this();
		in.copyFieldsTo(this);
	}

	public BaseObject() {
		for (PE pe : propNames())
			switch (pe.type()) {
			case BOOLEAN:
				properties.add(Boolean.FALSE.toString());
				break;
			case FLOAT:
				properties.add(Float.toString(0f));
				break;
			case INTEGER:
				properties.add(Integer.toString(0));
				break;
			case STRING:
				properties.add(new String());
				break;
			}
	}
	
	public void copyFieldsTo(BaseObject<T, PE> destination) {
		for (int i=0; i<properties.size(); i++)	destination.setProperty(i, getProperty(i));
	}

	public static int maxIndex(ArrayList<? extends BaseObject<?,?>> objs) {
		int i = 0;
		for (BaseObject<?,?> obj : objs)
			if (obj.index() > i)
				i = obj.index();
		return i;
	}
	
	public ArrayList<String> keys() {
		ArrayList<String> out; 
		if (parent() != null)
			out = parent().keys();
		else
			out = new ArrayList<String>();
		out.add(0, getId());
		return out;
	}
	
	public abstract BaseObject<?,?> parent();
	
}
